package dwei.view
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	
	import mx.core.Application;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	
	import dwei.core.timer.TimerMgr;
	import dwei.core.timer.TimerVO;

	public class UIMgr
	{
//============================================================================
//INITIALIZE
//============================================================================
		private static function init():void
		{
			_app = Application.application as Application;
			if (!_app.initialized) return _app.addEventListener(Event.ADDED_TO_STAGE, appInitialized_handler);
			_app.stage.addEventListener(Event.RESIZE, stageResize_handler);
			_size.addEventListener("change", sizeChanged_handler);
		}
		init();
//============================================================================
//PROPERTY
//============================================================================
		private static var _app:Application;
		private static const _size:UISize = new UISize();
		private static const _layerContainerMap:Object = {};
		private static const _uidDelayTimerMap:Object = {};
		private static const _uidRemovingUIMap:Object = {};
//============================================================================
//PUBILC
//============================================================================
		/**
		 * 添加IUI
		 * @param ui
		 * 
		 */		
		public static function addUI(ui:IUI):void
		{
			if (!(ui is UIComponent)) return;
			var container:UIContainer = _layerContainerMap[ui.layer];
			if (container == null)
			{
				container = new UIContainer();
				container.layer = ui.layer;
				_layerContainerMap[ui.layer] = container;
				_app.addChild(container);
				
				validateContainerDepth();
				if (_app.initialized) validateContainerSize();
			}
			var loop:DisplayObject;
			var length:int = container.numChildren;
			if (ui.exclude && length != 0)
			{
				for (var index:int = length - 1;index >= 0;index--)
				{
					loop = container.getChildAt(index);
					if (loop != ui && loop is IUI) container.removeChildAt(index);
				}
			}
			if (container.contains(ui as UIComponent))
			{
				container.setChildIndex(ui as UIComponent, container.numChildren - 1);
				if (_uidRemovingUIMap.hasOwnProperty(ui.uid))
				{
					TimerMgr.removeTimer(_uidRemovingUIMap[ui.uid]);
					delete _uidRemovingUIMap[ui.uid];
					showUI(ui);
				}
				else if (ui.delay != 0)
				{
					TimerMgr.removeTimer(_uidDelayTimerMap[ui.uid]);
					delete _uidDelayTimerMap[ui.uid];
					_uidDelayTimerMap[ui.uid] = TimerMgr.addTimer(ui.delay, uiDelayed_cb, ui);
				}
			}
			else
			{
				if (!UIComponent(ui).initialized)
					ui.addEventListener(FlexEvent.CREATION_COMPLETE, uiInitialized_handler);
				else
					ui.addEventListener(Event.ADDED_TO_STAGE, uiAddedToStage_handler);
				container.addChild(ui as UIComponent);
			}
		}
		/**
		 * 删除指定IUI
		 * @param ui
		 * 
		 */		
		public static function removeUI(ui:IUI):void
		{
			if (!(ui is UIComponent)) return;
			if (_uidRemovingUIMap.hasOwnProperty(ui.uid)) return;
			var container:UIContainer = _layerContainerMap[ui.layer];
			if (container == null || !container.contains(ui as UIComponent)) return;
			if (_uidDelayTimerMap.hasOwnProperty(ui.uid))
			{
				TimerMgr.removeTimer(_uidDelayTimerMap[ui.uid]);
				delete _uidDelayTimerMap[ui.uid];
			}
			if ((ui.addedEffect != null) && (ui.addedEffect.isPlaying)) ui.addedEffect.stop();
			if (ui.removedEffect != null)
			{
				_uidRemovingUIMap [ui.uid] = TimerMgr.addTimer(ui.removedEffect.duration, removed_cb, ui);
				ui.removedEffect.play([ui]);
			}
			else
				hideUI(ui);
		}
		/**
		 * 判断指定IUI是否已存在
		 * @param ui
		 * @return 
		 * 
		 */		
		public static function hasUI(ui:IUI):Boolean
		{
			if (ui == null) return false;
			if (_uidRemovingUIMap.hasOwnProperty(ui.uid)) return false;
			var container:UIContainer = _layerContainerMap[ui.layer];
			if (container == null) return false;
			return container.contains(ui as DisplayObject);
		}
		/**
		 * 获取指定层的所有IUI
		 * @param layer
		 * @return 
		 * 
		 */		
		public static function getChildrenInLayer(layer:uint):Array
		{
			var children:Array = [];
			var container:UIContainer = _layerContainerMap[layer];
			if (container == null) return children;
			var length:int = container.numChildren;
			for (var index:int = 0;index < length;index++)
			{
				children.push(container.getChildAt(index));
			}
			return children;
		}
//============================================================================
//PRIVATE
//============================================================================
		private static function validateContainerDepth():void
		{
			var container:UIContainer;
			var containers:Array = [];
			var index:int = _app.numChildren - 1;
			while (index > -1)
			{
				container = _app.getChildAt(index--) as UIContainer;
				if (container != null && (_layerContainerMap[container.layer] == container)) containers.push(container);
			}
			containers.sortOn("layer", Array.NUMERIC);
			var indexTop:int = _app.numChildren - 1;
			var length:int = containers.length;
			for (index = 0;index < length;index++)
			{
				_app.setChildIndex(containers[index], indexTop);
			}
		}
		private static function validateContainerSize():void
		{
			var container:UIContainer;
			var containers:Array = [];
			var index:int = _app.numChildren - 1;
			while (index > -1)
			{
				container = _app.getChildAt(index--) as UIContainer;
				if (container != null && (_layerContainerMap[container.layer] == container)) containers.push(container);
			}
			
			var x:int;
			var y:int;
			var ui:DisplayObject;
			for (index = 0;index < containers.length;index++)
			{
				ui = containers[index];
				ui.width = Math.max(_size.minWidth, Math.min(_size.maxWidth, _app.width));
				ui.height = Math.max(_size.minHeight, Math.min(_size.maxHeight, _app.height));
				
				x = ui.x;
				switch (_size.horizontalAlign)
				{
					case UISize.LEFT:
						x = 0;
						break;
					case UISize.CENTER:
						x = Math.max(0, (_app.stage.stageWidth - ui.width) / 2);
						break;
					case UISize.RIGHT:
						x = _app.stage.stageWidth - ui.width;
						break;
				}
				y = ui.y;
				switch (_size.verticalAlign)
				{
					case UISize.TOP:
						y = 0;
						break;
					case UISize.MIDDLE:
						y = Math.max(0, (_app.stage.stageHeight- ui.height) / 2);
						break;
					case UISize.BOTTOM:
						y = _app.stage.stageHeight - ui.height;
						break;
				}
				ui.x = x;
				ui.y = y;
			}
		}
		private static function showUI(ui:IUI):void
		{
			var container:UIContainer = _layerContainerMap[ui.layer];
			if (container == null) return;
			if (!container.contains(ui as UIComponent)) return;
			if ((ui.removedEffect != null) && (ui.removedEffect.isPlaying)) ui.removedEffect.stop();
			var delay:uint = 0;
			if (ui.addedEffect != null)
			{
				ui.addedEffect.play([ui]);
				delay = ui.addedEffect.duration;
			}
			if (ui.delay != 0) _uidDelayTimerMap[ui.uid] = TimerMgr.addTimer(delay + ui.delay, uiDelayed_cb, ui);
		}
		private static function hideUI(ui:IUI):void
		{
			var container:UIContainer = _layerContainerMap[ui.layer];
			container.removeChild(ui as UIComponent);
			if (container.numChildren > 1) return;
			_app.removeChild(container);
			delete _layerContainerMap[ui.layer];
		}
//============================================================================
//HANDLER
//============================================================================
		private static function appInitialized_handler(event:Event):void
		{
			_app.removeEventListener(Event.ADDED_TO_STAGE, appInitialized_handler);
			_app.stage.addEventListener(Event.RESIZE, stageResize_handler);
			_size.addEventListener("change", sizeChanged_handler);
			validateContainerSize();
		}
		private static function stageResize_handler(event:Event):void
		{
			validateContainerSize();
		}
		private static function sizeChanged_handler(event:Event):void
		{
			validateContainerSize();
		}
		
		private static function uiInitialized_handler(event:FlexEvent):void
		{
			var ui:IUI = event.currentTarget as IUI;
			ui.removeEventListener(FlexEvent.CREATION_COMPLETE, uiInitialized_handler);
			showUI(ui);
		}
		private static function uiAddedToStage_handler(event:Event):void
		{
			var ui:IUI = event.currentTarget as IUI;
			ui.removeEventListener(Event.ADDED_TO_STAGE, uiAddedToStage_handler);
			showUI(ui);
		}
//============================================================================
//CALLBACK
//============================================================================
		private static function uiDelayed_cb(vo:TimerVO):void
		{
			delete _uidDelayTimerMap[IUI(vo.data).uid];
			removeUI(vo.data as IUI);
		}
		private static function removed_cb(vo:TimerVO):void
		{
			delete _uidRemovingUIMap[IUI(vo.data).uid];
			hideUI(vo.data as IUI);
		}
//============================================================================
//GETTER/SETTER
//============================================================================
		public static function get size():UISize
		{
			return _size;
		}

	}
}